;;;; Created on 2007-09-08 12:42:20
;;;; business logic class library

(in-package :gtcup)

(clsql:disable-sql-reader-syntax)
(clsql:enable-sql-reader-syntax)

(defun import-result-file (file-name campeonato-id)
  (with-open-file (stream file-name)
    (let ((line nil)
	  (corrida nil)
	  (nome-corrida nil)
	  (data-corrida nil)
	  (nome-piloto nil)
	  (piloto nil)
	  (laps nil)
	  (bestlap nil)
	  (racetime nil)
	  (lap-distance nil)
	  (resultado nil))
      (loop
       (setf line (read-line stream nil))
       (when (not line) 
	 (return))
       
       (when (import-get-value line "[Slot")
         (setf nome-piloto nil)
         (setf piloto nil)
         (setf laps nil)
         (setf bestlap nil)
         (setf racetime nil)
         (setf lap-distance nil)
         (setf resultado nil))
       
       (when (not nome-corrida)
	 (setf nome-corrida (import-get-value line "Scene=")))
       (when (not data-corrida)
	 (setf data-corrida (import-get-value line "TimeString=")))
       (when (not nome-piloto)
	 (setf nome-piloto (import-get-value line "Driver=")))
       (when (not laps)
	 (setf laps (import-get-value line "Laps=")))
       (when (not bestlap)
	 (setf bestlap (import-get-value line "BestLap=")))
       (when (not racetime)
	 (setf racetime (import-get-value line "RaceTime=")))
       (when (not lap-distance)
	 (setf lap-distance (import-get-value line "LapDistanceTravelled=")))
       
       (when nome-corrida
	 (when data-corrida
	   (when (not corrida)
	     (setf corrida (make-instance 'corrida 
	                                  :nome (remove-path-from-corrida nome-corrida)
					  :data (clsql:parse-timestring data-corrida)
	                                  :campeonato-id campeonato-id))
	     (pretty-print corrida)
	     (setf corrida (save corrida)))))
       
       (when nome-piloto
	 (when (not piloto)
	   (setf piloto (make-instance 'piloto
					:nome nome-piloto))
	   (pretty-print piloto)
	   (setf piloto (save piloto))))
	   
       (when laps
	 (when racetime
	   (when lap-distance
	     (when (not resultado)
	       (setf resultado (create-resultado laps racetime lap-distance bestlap))
	       (setf (piloto-id resultado) (id piloto))
	       (setf (corrida-id resultado) (id corrida))
	       (pretty-print resultado)
	       (save resultado)))))))))

 


  
  
(defun import-get-value (line tag)
  (when (search tag line)
    (subseq line (length tag) (- (length line) 1))))

(defun remove-path-from-corrida (nome-corrida)
  (let ((posicao (position #\\ nome-corrida :test #'equalp :from-end t)))
    (if (equalp posicao nil) 
	(print nome-corrida)
	(subseq nome-corrida (+ posicao 1)))))
	

;;; Method to save an entity

(defgeneric save (self))

(defmethod save ((self corrida))
  (let ((corrida-banco (load-corrida-by-name (nome self) (data self))))
    (when (equalp corrida-banco nil)
      (clsql:update-records-from-instance self))
    (load-corrida-by-name (nome self) (data self))))

(defmethod save ((self piloto))
  (let ((piloto-banco (load-piloto-by-name (nome self))))
    (when (equalp piloto-banco nil)
      (clsql:update-records-from-instance self))
    (load-piloto-by-name (nome self))))

(defmethod save ((self resultado))
  (clsql:update-records-from-instance self)
  (clsql:select 'resultado))

(defmethod save ((self campeonato))
  (clsql:update-records-from-instance self)
  (clsql:select 'campeonato :where [= [slot-value 'campeonato 'nome] (nome self)]))

(defmethod save ((self pontuacao))
  (clsql:update-records-from-instance self)
  (clsql:select 'resultado :where 
		[= [slot-value 'pontuacao 'campeonato-id] (campeonato-id self)]))
 
(defmethod save ((self circuito))
  (clsql:update-records-from-instance self)
  (clsql:select 'circuito :where [= [slot-value 'circuito 'arquivo] (arquivo self)]))


;; Cria um resultado
(defun create-resultado (voltas tempo-corrida distancia-ultima-volta melhor-volta)
  (make-instance 'resultado
		 :melhor-volta melhor-volta
		 :distancia-ultima-volta (parse-number distancia-ultima-volta)
		 :voltas (parse-integer voltas)
		 :tempo-corrida tempo-corrida))

(defun load-piloto-by-name (name)
  (let ((results (clsql:select 'piloto :where [= [slot-value 'piloto 'nome] name])))
    (when (equalp results nil) (setf results '((nil))))
    (car (car results))))

(defun load-corrida-by-name (nome data)
  (let ((results (clsql:select 'corrida :where 
			       [and 
			       [= [slot-value 'corrida 'nome] nome]
			       [= [slot-value 'corrida 'data] data]])))
    (when (equalp results nil) (setf results '((nil))))
    (print results)
    (car (car results))))

;; Carrega um circuito pelo nome do arquivo
(defun load-circuito-by-arquivo (nome-arquivo)
  (let ((results (clsql:select 'circuito :where 
			       [= [slot-value 'circuito 'arquivo] nome-arquivo])))
    (when (equalp results nil) (setf results '((nil))))
    (car (car results))))

(defun load-resultados-by-corrida (corrida-id)
  (let ((resultados (clsql:select 'resultado 
				  :where 
				  [= [slot-value 'resultado 'corrida-id] 
				  corrida-id] 
				:order-by '(([voltas] :desc) ([tempo-corrida] :asc)))))
    (when (equalp resultados nil) (setf resultados '((nil))))
    resultados))

(defun save-pontuacao-by-corrida (corrida)
  (let ((resultados (load-resultados-by-corrida (id corrida)))
	(posicao 0))
    (dolist (resultado resultados)
      (incf posicao)
      (setf (posicao (car resultado)) posicao)
      (save (car resultado)))))

(defun load-pontuacao-by-campeonato-posicao (campeonato posicao)
  (let ((pontuacao (clsql:select 'pontuacao :where 
				 [and 
				 [= [slot-value 'pontuacao 'campeonato-id] (id campeonato)] 
				 [= [slot-value 'pontuacao 'posicao] posicao]]))) 
    (if pontuacao (pontos (car (car pontuacao))) 0)))

(defun list-piloto-pontuacao-by-campeonato (campeonato)
  (let ((classificacao (make-hash-table))
	(lista-classificacao '()))
    (dolist (corrida (corridas campeonato))
      (dolist (resultado (resultados corrida))
	(let ((pontos 0))
	  (dolist (pontuacao (pontuacoes campeonato))
	    (if (equalp (posicao pontuacao) (posicao resultado)) 
		(setf pontos (pontos pontuacao))))
	  (setf (gethash (nome (piloto resultado)) classificacao) 
		(incf pontos 
		      (if (gethash (nome (piloto resultado)) classificacao)
			  (gethash (nome (piloto resultado)) classificacao) 
			  0))))))
    (maphash #'(lambda (key value) 
		 (setf lista-classificacao (append lista-classificacao (list (list value key))))) classificacao)
    (sort lista-classificacao #'> :key #'car)))

	  
	      
